#include "cocosExtension.h"

namespace   cocos2d {

enum {
	kSceneFade = 0xFADEFADE,
};

#define IMPLEMENT_TRANSITIONWITHDURATION(_Type)\
    _Type* _Type::transitionWithDuration(ccTime t, CCScene* scene)\
{\
    _Type* pScene = new _Type();\
	if(pScene && pScene->initWithDuration(t, scene)){\
    pScene->autorelease();\
	return pScene;}\
	CC_SAFE_DELETE(pScene);\
	return NULL;\
}

// vector utils 

CCPoint subVec2( CCPoint p1, CCPoint p2 )
{
	return ccp( p1.x - p2.x, p1.y - p2.y );
}

CCPoint addVec2( CCPoint p1, CCPoint p2 )
{
	return ccp( p1.x + p2.x, p1.y + p2.y );
}

CCPoint multVec2( CCPoint p1, float k )
{
	return ccp( p1.x* k, p1.y * k );
}

float NormeVec2( CCPoint p1 )
{
	return sqrt( p1.x*p1.x + p1.y*p1.y );
}

CCPoint NormalizeVec2( CCPoint p1 )
{
	float norme = NormeVec2(p1);
	return ccp( p1.x / norme , p1.y / norme );
}

CCPoint	setNormeVec2( CCPoint p1, float lenght )
{
	return multVec2( NormalizeVec2( p1 ) , lenght );
}

// vector 3 utils

ccVertex3F subVec3( ccVertex3F p1, ccVertex3F p2 )
{
	return vertex3( p1.x - p2.x, p1.y - p2.y, p1.z - p2.z );
}

ccVertex3F addVec3( ccVertex3F p1, ccVertex3F p2 )
{
	return vertex3( p1.x + p2.x, p1.y + p2.y, p1.z + p2.z  );
}

ccVertex3F multVec3( ccVertex3F p1, float k )
{
	return vertex3( p1.x* k, p1.y * k , p1.z * k );
}

float NormeVec3( ccVertex3F p1 )
{
	return sqrt( p1.x*p1.x + p1.y*p1.y + p1.z*p1.z );
}

ccVertex3F NormalizeVec3( ccVertex3F p1 )
{
	float norme = NormeVec3(p1);
	return vertex3( p1.x / norme , p1.y / norme, p1.z / norme );
}

ccVertex3F setNormeVec3( ccVertex3F p1, float lenght )
{
	return multVec3( NormalizeVec3( p1 ) , lenght );
}



//
// GravityGrid Transition
//
CCTransitionGravityGrid::CCTransitionGravityGrid()
{
}
CCTransitionGravityGrid::~CCTransitionGravityGrid()
{
}


CCActionInterval* CCTransitionGravityGrid::action()
{
	return CCGravityGrid::actionWithGrid(5, m_fDuration/2.0f);
}

IMPLEMENT_TRANSITIONWITHDURATION(CCTransitionGravityGrid)








// implementation of CCGravityGrid

CCGravityGrid* CCGravityGrid::actionWithGrid(int nGrid, cocos2d::ccTime duration)
{
	CCGravityGrid *pAction = new CCGravityGrid();

	if (pAction)
	{
		if (pAction->initWithGrid(nGrid, duration))
		{
			pAction->autorelease();
		}
		else
		{
			CC_SAFE_RELEASE_NULL(pAction);
		}
	}

	return pAction;
}

bool CCGravityGrid::initWithGrid(int nGrid, cocos2d::ccTime duration)
{
	nGrid = nGrid;

	return CCTiledGrid3DAction::initWithSize(ccg(nGrid, nGrid), duration);
}
/*
CCObject* CCGravityGrid::copyWithZone(cocos2d::CCZone *pZone)
{
	CCZone* pNewZone = NULL;
	CCGravityGrid* pCopy = NULL;
	if(pZone && pZone->m_pCopyObject) 
	{
		pCopy = (CCGravityGrid*)(pZone->m_pCopyObject);
	}
	else
	{
		pCopy = new CCGravityGrid();
		pZone = pNewZone = new CCZone(pCopy);
	}

	CCTiledGrid3DAction::copyWithZone(pZone);

	pCopy->initWithGrid(m_nGrid, m_fDuration);

	CC_SAFE_DELETE(pNewZone);
	return pCopy;
}
*/
void CCGravityGrid::startWithTarget(CCNode *pTarget)
{
	CCTiledGrid3DAction::startWithTarget(pTarget);
	m_winSize = CCDirector::sharedDirector()->getWinSizeInPixels();

	///

	BlackHolePos = ccp( 240.0f, 160.0f );
	MaxDist = max(
					max( 
						NormeVec2( subVec2( BlackHolePos , ccp(480.0f, 320.0f )  ) ) ,
						NormeVec2( subVec2( BlackHolePos , ccp(480.0f, 0.0f ) ) ) 
						)
				,
					max( 
						NormeVec2( subVec2( BlackHolePos , ccp(0.0f, 320.0f )  ) ) ,
						NormeVec2( subVec2( BlackHolePos , ccp(0.0f, 0.0f ) ) ) 
						) 
				);

	///

	BlackHolePos3d = vertex3( 240.0f, 160.0f, -1000.0f );
	MaxDist3d = max(
					max( 
						NormeVec3( subVec3( BlackHolePos3d , vertex3(480.0f, 320.0f, 0.0f )  ) ) ,
						NormeVec3( subVec3( BlackHolePos3d , vertex3(480.0f, 0.0f, 0.0f ) ) ) 
						)
				,
					max( 
						NormeVec3( subVec3( BlackHolePos3d , vertex3(0.0f, 320.0f, 0.0f )  ) ) ,
						NormeVec3( subVec3( BlackHolePos3d , vertex3(0.0f, 0.0f, 0.0f ) ) ) 
						) 
				);
}

void CCGravityGrid::update(cocos2d::ccTime time)
{
	int j;

	printf ( " CCGravityGrid::update   time :  %f \n ", time );

	for( int i=0; i < m_sGridSize.x; ++i )
	{
		for (j = 0; j < m_sGridSize.y; ++j)
		{
			ccQuad3 coords = originalTile(ccg(i, j));

			CCPoint realdirection = ccp( 0.0f,0.0f );
			CCPoint direction = ccp( 0.0f,0.0f );
			float dist = 0.0f;
			//float MaxDist = 577.0f;
			float coef = 0.0f;
			

			CCPoint balcHolePos = BlackHolePos; //ccp( 480.0f, 0.0f );

			///

			realdirection = direction = ccp( balcHolePos.x - coords.bl.x  , balcHolePos.y - coords.bl.y );
			dist = sqrt( direction.x*direction.x + direction.y*direction.y );
			direction = ccp( (direction.x / dist) * MaxDist , (direction.y / dist) * MaxDist );
			coef = (time*time);
			
			coords.bl.x += realdirection.x >= 0.0f ? min( direction.x * coef, realdirection.x ) : max ( direction.x * coef, realdirection.x ) ;
			coords.bl.y += realdirection.y >= 0.0f ? min( direction.y * coef, realdirection.y ) : max ( direction.y * coef, realdirection.y ) ;

			///

			realdirection = direction = ccp( balcHolePos.x - coords.br.x   , balcHolePos.y - coords.br.y  );
			dist = sqrt( direction.x*direction.x + direction.y*direction.y );
			direction = ccp( (direction.x / dist) * MaxDist , (direction.y / dist) * MaxDist );
			//coef = (time*time);

			coords.br.x += realdirection.x >= 0.0f ? min( direction.x * coef, realdirection.x ) : max ( direction.x * coef, realdirection.x ) ;
			coords.br.y += realdirection.y >= 0.0f ? min( direction.y * coef, realdirection.y ) : max ( direction.y * coef, realdirection.y ) ;

			///

			realdirection = direction = ccp( balcHolePos.x - coords.tl.x , balcHolePos.y - coords.tl.y );
			dist = sqrt( direction.x*direction.x + direction.y*direction.y );
			direction = ccp( (direction.x / dist) * MaxDist , (direction.y / dist) * MaxDist );
			//coef = (time*time);

			coords.tl.x += realdirection.x >= 0.0f ? min( direction.x * coef, realdirection.x ) : max ( direction.x * coef, realdirection.x ) ;
			coords.tl.y += realdirection.y >= 0.0f ? min( direction.y * coef, realdirection.y ) : max ( direction.y * coef, realdirection.y ) ;

			///

			realdirection = direction = ccp( balcHolePos.x - coords.tr.x , balcHolePos.y - coords.tr.y );
			dist = sqrt( direction.x*direction.x + direction.y*direction.y );
			direction = ccp( (direction.x / dist) * MaxDist , (direction.y / dist) * MaxDist );
			//coef = (time*time);

			coords.tr.x += realdirection.x >= 0.0f ? min( direction.x * coef, realdirection.x ) : max ( direction.x * coef, realdirection.x ) ;
			coords.tr.y += realdirection.y >= 0.0f ? min( direction.y * coef, realdirection.y ) : max ( direction.y * coef, realdirection.y ) ;

			///

			setTile(ccg(i, j), coords);
		}
	}
}


void CCGravityGrid::update3d(cocos2d::ccTime time)
{
	int j;

	printf ( " CCGravityGrid::update   time :  %f \n ", time );

	for( int i=0; i < m_sGridSize.x; ++i )
	{
		for (j = 0; j < m_sGridSize.y; ++j)
		{
			ccQuad3 coords = originalTile(ccg(i, j));

			ccVertex3F realdirection = vertex3( 0.0f,0.0f, 0.0f );
			ccVertex3F direction = vertex3( 0.0f,0.0f, 0.0f );
			float dist = 0.0f;
			float coef = 0.0f;
			float coef2 = 0.0f;
			///

			realdirection = direction =  subVec3( BlackHolePos3d, coords.bl );
			dist = NormeVec3( direction ) ;
			direction = setNormeVec3( direction, MaxDist );
			coef = (time*time);
			coef2 = (time*time*time*time*time*time*time*time*time*time*time*time);
			
			coords.bl.x += realdirection.x >= 0.0f ? min( direction.x * coef, realdirection.x ) : max ( direction.x * coef, realdirection.x ) ;
			coords.bl.y += realdirection.y >= 0.0f ? min( direction.y * coef, realdirection.y ) : max ( direction.y * coef, realdirection.y ) ;
			coords.bl.z += realdirection.z >= 0.0f ? min( direction.z * coef2, realdirection.z ) : max ( direction.z * coef2, realdirection.z ) ;

			///

			realdirection = direction =  subVec3( BlackHolePos3d, coords.br );
			dist = NormeVec3( direction ) ;
			direction = setNormeVec3( direction, MaxDist );
			coef = (time*time);
			
			coords.br.x += realdirection.x >= 0.0f ? min( direction.x * coef, realdirection.x ) : max ( direction.x * coef, realdirection.x ) ;
			coords.br.y += realdirection.y >= 0.0f ? min( direction.y * coef, realdirection.y ) : max ( direction.y * coef, realdirection.y ) ;
			coords.br.z += realdirection.z >= 0.0f ? min( direction.z * coef2, realdirection.z ) : max ( direction.z * coef2, realdirection.z ) ;

			///

			realdirection = direction =  subVec3( BlackHolePos3d, coords.tl );
			dist = NormeVec3( direction ) ;
			direction = setNormeVec3( direction, MaxDist );
			coef = (time*time);
			
			coords.tl.x += realdirection.x >= 0.0f ? min( direction.x * coef, realdirection.x ) : max ( direction.x * coef, realdirection.x ) ;
			coords.tl.y += realdirection.y >= 0.0f ? min( direction.y * coef, realdirection.y ) : max ( direction.y * coef, realdirection.y ) ;
			coords.tl.z += realdirection.z >= 0.0f ? min( direction.z * coef2, realdirection.z ) : max ( direction.z * coef2, realdirection.z ) ;

			///

			realdirection = direction =  subVec3( BlackHolePos3d, coords.tr );
			dist = NormeVec3( direction ) ;
			direction = setNormeVec3( direction, MaxDist );
			coef = (time*time);
			
			coords.tr.x += realdirection.x >= 0.0f ? min( direction.x * coef, realdirection.x ) : max ( direction.x * coef, realdirection.x ) ;
			coords.tr.y += realdirection.y >= 0.0f ? min( direction.y * coef, realdirection.y ) : max ( direction.y * coef, realdirection.y ) ;
			coords.tr.z += realdirection.z >= 0.0f ? min( direction.z * coef2, realdirection.z ) : max ( direction.z * coef2, realdirection.z ) ;

			///

			setTile(ccg(i, j), coords);
		}
	}
}

}